package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/gorilla/schema"
	"github.com/gorilla/sessions"
)

func main() {
	r := mux.NewRouter()
	// Add your routes as needed
	r.HandleFunc("/api/{method}", Handle)
	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./")))

	srv := &http.Server{
		Addr:    "0.0.0.0:8080",
		Handler: r,
	}

	if err := srv.ListenAndServe(); err != nil {
		log.Println(err)
	}
}

var decoder = schema.NewDecoder()

type Ret struct {
	RetCode int         `json:"ret"`
	Message string      `json:"msg"`
	Data    interface{} `json:"data"`
}

var store = sessions.NewCookieStore([]byte("secret-encryp"))

func Handle(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	method, ok := vars["method"]
	if !ok {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	s, _ := store.Get(r, "skywalkID")
	if _, ok := s.Values["user"]; !ok && method != "login" {
		http.Redirect(w, r, "/", http.StatusUnauthorized)
		return
	}

	server, ok := registerServer[method]
	if !ok {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	var err error
	err = r.ParseForm()
	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	req := server.MakeRequest()
	if req != nil {
		err = decoder.Decode(req, r.PostForm)
		if err != nil {
			w.WriteHeader(http.StatusNotFound)
			return
		}
	}

	rsp := server.Handle(req)
	ret := &Ret{
		RetCode: 0,
		Message: "ok",
		Data:    rsp,
	}

	b, err := json.Marshal(ret)
	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	if method == "login" {
		sessions.Save(r, w)
	}

	w.Write(b)
}

type Server interface {
	MakeRequest() interface{}
	Handle(interface{}) interface{}
}

var registerServer = map[string]Server{}

func RegisterServer(m string, s Server) {
	if _, ok := registerServer[m]; ok {
		panic(fmt.Sprintf("duplicate method:%s", m))
	}
	registerServer[m] = s
}

/////////////////////////////

func init() {
	RegisterServer("login", &loginServer{})
	RegisterServer("view", &viewServer{})
}

type LoginRequest struct {
	Account  string `schema:"acc"`
	Password string `schema:"pas"`
	Remember int    `schema:"remember"`
}

type LoginResponse struct {
	Account  string `json:"acc"`
	Password string `json:"pas"`
}

type loginServer struct{}

func (this *loginServer) MakeRequest() interface{} {
	return new(LoginRequest)
}

func (this *loginServer) Handle(r interface{}) interface{} {
	req := r.(*LoginRequest)
	fmt.Println("Request", req)

	// auth success
	//if req.Remember == 0 {
	//sessions.Options.MaxAge = 0
	//} else {
	//sessions.Options.MaxAge = 15 * 24 * 60 * 60
	//}

	return &LoginResponse{req.Account, req.Password}
}

/////////////////////////////
type ViewRequest struct {
	Message string `schema:"msg"`
}

type ViewResponse struct {
	Message string `json:"msg"`
}

type viewServer struct{}

func (this *viewServer) MakeRequest() interface{} {
	return new(ViewRequest)
}

func (this *viewServer) Handle(r interface{}) interface{} {
	req := r.(*ViewRequest)
	fmt.Println("Request", req)
	return &ViewResponse{req.Message}
}
